feat(cli): add --experimental-bundle opt-in for Vite bundled dev mode#1413
Draft
stipsan wants to merge 6 commits into
Draft
feat(cli): add --experimental-bundle opt-in for Vite bundled dev mode#1413stipsan wants to merge 6 commits into
stipsan wants to merge 6 commits into
Conversation
Adds a typed `experimental.bundledDev` option to the CLI config type and zod schema so `sanity.cli.ts` can opt into Vite's bundled dev mode without the value being stripped on parse.
Adds a `--experimental-bundle` flag to `sanity dev` and honors `experimental.bundledDev` from sanity.cli.ts. The flag wins when set (including `--no-experimental-bundle`), otherwise the config value is used, defaulting to off. When enabled, `experimental.bundledDev` is set on the inline Vite config before user vite config is applied.
Contributor
📦 Bundle Stats —
|
| Metric | Value | vs main (3801bd7) |
|---|---|---|
| Internal (raw) | 2.7 KB | - |
| Internal (gzip) | 1.0 KB | - |
| Bundled (raw) | 11.16 MB | +93 B, +0.0% |
| Bundled (gzip) | 2.10 MB | +19 B, +0.0% |
| Import time | 911ms | +11ms, +1.2% |
bin:sanity
| Metric | Value | vs main (3801bd7) |
|---|---|---|
| Internal (raw) | 782 B | - |
| Internal (gzip) | 423 B | - |
| Bundled (raw) | 9.87 MB | - |
| Bundled (gzip) | 1.78 MB | - |
| Import time | 2.30s | +1.35s, +142.5% |
🗺️ View treemap · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
📦 Bundle Stats — @sanity/cli-core
Compared against main (3801bd7e)
| Metric | Value | vs main (3801bd7) |
|---|---|---|
| Internal (raw) | 106.8 KB | +93 B, +0.1% |
| Internal (gzip) | 26.7 KB | +37 B, +0.1% |
| Bundled (raw) | 21.72 MB | +85 B, +0.0% |
| Bundled (gzip) | 3.46 MB | +20 B, +0.0% |
| Import time | 794ms | -11ms, -1.3% |
🗺️ View treemap · Artifacts
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
📦 Bundle Stats — create-sanity
Compared against main (3801bd7e)
| Metric | Value | vs main (3801bd7) |
|---|---|---|
| Internal (raw) | 908 B | - |
| Internal (gzip) | 483 B | - |
| Bundled (raw) | 931 B | - |
| Bundled (gzip) | 491 B | - |
| Import time | ❌ ChildProcess denied: node | - |
Details
- Import time regressions over 10% are flagged with
⚠️ - Sizes shown as raw / gzip 🗜️. Internal bytes = own code only. Total bytes = with all dependencies. Import time = Node.js cold-start median.
Contributor
Coverage Delta
Comparing 4 changed files against main @ Overall Coverage
|
Vite bundled dev mode bundles from an HTML entry, defaulting to `<root>/index.html`. Sanity serves a virtual document (rewritten to `.sanity/runtime/index.html`), so without an explicit entry the bundle fails with UNRESOLVED_ENTRY. Set `build.rolldownOptions.input` to the runtime HTML when bundled mode is enabled.
vite@8.1.3 resolves rolldown@1.1.4, which fixes the namespace-import codegen bug that crashed `sanity dev --experimental-bundle` at runtime (allConstants is not defined, from focus-lock via @sanity/ui). Also adds rolldown/@rolldown/* to minimumReleaseAgeExclude, matching vite's own entry, so vite's ~x.y.z rolldown range can resolve fresh patch fixes.
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Adds an opt-in for Vite 8.1's experimental bundled dev mode to
sanity dev. When enabled, Vite serves a Rolldown-bundled app during development instead of the unbundled per-module ESM dev server.Because
sanity devbuilds its Vite config programmatically (configFile: false), the option can't be set via a uservite.config.*. This exposes it two ways:sanity dev --experimental-bundle(and--no-experimental-bundleto force off).experimental: { bundledDev: true }insanity.cli.ts(persistent across runs).Resolution is flag-first, then config, then off (mirrors how host/port/basePath resolve). The
sanity.cli.tsoption required addingexperimental.bundledDevto theCliConfigtype and the zodcliConfigSchemain@sanity/cli-core— otherwise the parser strips unknown keys before the value reaches the dev server.Two things are set on the inline dev config when enabled (before user
viteconfig is merged, so a user override keeps final say):experimental.bundledDev = truebuild.rolldownOptions.input = <root>/.sanity/runtime/index.html— bundled mode bundles from an HTML entry and defaults to<root>/index.html, which doesn't exist in a Sanity project (the studio HTML is virtual, served from.sanity/runtime/index.html). Pointing the bundler at the real runtime HTML is the intended integration per Vite's bundled-dev design doc. Without it, bundled mode fails immediately withUNRESOLVED_ENTRY.Also bumps the vite catalog to
^8.1.3and addsrolldown/@rolldown/*tominimumReleaseAgeExclude(matching the existingviteentry) — see below.It works end-to-end now (vite 8.1.3 + rolldown 1.1.4)
Earlier revisions of this PR documented an upstream crash: on vite 8.1.0–8.1.2 (rolldown ≤1.1.3), the bundled studio threw
ReferenceError: allConstants is not defined— Rolldown's lazy-barrel dev codegen mis-compiled a pure-ESMimport * asnamespace import infocus-lock(transitive dep of@sanity/ui; tracked around vitejs/vite#22756 and friends).rolldown@1.1.4(2026-07-01) disables lazy barrel in dev mode (rolldown#10060, #10071), which fixes it. Withvite@8.1.3resolvingrolldown@1.1.4, the studio now renders correctly in bundled dev mode: the brokenvar constants = allConstants;no longer appears in the served bundle, and the browser console has no ReferenceErrors (only the expected CORS errors for an unregistered studio).The
minimumReleaseAgeExcludeaddition is needed because the repo's 3-day release-age gate would otherwise hold vite'srolldown: ~1.1.3range at the broken 1.1.3 until fresh rolldown patches age out; rolldown is vite's own bundler (same trust domain/cadence as the existingviteexclusion).bundled_dev_mode_studio_renders_vite813.mp4
What to review
@sanity/cli-core: newexperimental.bundledDevfield in theCliConfigtype andcliConfigSchema.@sanity/cli: new--experimental-bundleflag onDevCommand; resolution ingetDevServerConfig(flag → config → off) with an info notice; application ofexperimental.bundledDev+build.rolldownOptions.inputinstartDevServer.pnpm-workspace.yaml: vite catalog^8.1.2→^8.1.3;rolldown/@rolldown/*added tominimumReleaseAgeExclude.Testing
Automated:
@sanity/cli-core:experimental.bundledDevsurvives config parse instead of being stripped.getDevServerConfig: flag → config → off resolution,--no-experimental-bundleoverride, info notice.devServer.test.ts:createServerreceivesexperimental.bundledDev: trueand the runtime-HTML entry only when enabled, preserves other experimental options, and still applies user vite config afterward.pnpm check:types,pnpm check:lint,pnpm check:depspass onvite@8.1.3.Manual (
fixtures/basic-studio):sanity dev --experimental-bundleon vite 8.1.3: boots, serves bundled/assets/index.js, and the studio renders and is interactive in Chrome with no ReferenceErrors (see video). Same behavior via thesanity.cli.tsopt-in.sanity devis unaffected (serves/@vite/client+ unbundledapp.js).Studio renders in bundled dev mode on vite 8.1.3
Normal sanity dev renders the studio (no regression)
To show artifacts inline, enable in settings.